<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "https://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" lang="en-US">
<head>
<meta http-equiv="Content-Type" content="text/xhtml;charset=UTF-8"/>
<meta http-equiv="X-UA-Compatible" content="IE=11"/>
<meta name="generator" content="Doxygen 1.9.8"/>
<meta name="viewport" content="width=device-width, initial-scale=1"/>
<title>libcoap: coap_observe(3)</title>
<link href="tabs.css" rel="stylesheet" type="text/css"/>
<script type="text/javascript" src="jquery.js"></script>
<script type="text/javascript" src="dynsections.js"></script>
<link href="navtree.css" rel="stylesheet" type="text/css"/>
<script type="text/javascript" src="resize.js"></script>
<script type="text/javascript" src="navtreedata.js"></script>
<script type="text/javascript" src="navtree.js"></script>
<link href="search/search.css" rel="stylesheet" type="text/css"/>
<script type="text/javascript" src="search/searchdata.js"></script>
<script type="text/javascript" src="search/search.js"></script>
<link href="doxygen.css" rel="stylesheet" type="text/css" />
</head>
<body>
<div id="top"><!-- do not remove this div, it is closed by doxygen! -->
<div id="titlearea">
<table cellspacing="0" cellpadding="0">
 <tbody>
 <tr id="projectrow">
  <td id="projectalign">
   <div id="projectname">libcoap<span id="projectnumber">&#160;4.2.0</span>
   </div>
  </td>
 </tr>
 </tbody>
</table>
</div>
<!-- end header part -->
<!-- Generated by Doxygen 1.9.8 -->
<script type="text/javascript">
/* @license magnet:?xt=urn:btih:d3d9a9a6595521f9666a5e94cc830dab83b65699&amp;dn=expat.txt MIT */
var searchBox = new SearchBox("searchBox", "search/",'.html');
/* @license-end */
</script>
<script type="text/javascript" src="menudata.js"></script>
<script type="text/javascript" src="menu.js"></script>
<script type="text/javascript">
/* @license magnet:?xt=urn:btih:d3d9a9a6595521f9666a5e94cc830dab83b65699&amp;dn=expat.txt MIT */
$(function() {
  initMenu('',true,false,'search.php','Search');
  $(document).ready(function() { init_search(); });
});
/* @license-end */
</script>
<div id="main-nav"></div>
</div><!-- top -->
<div id="side-nav" class="ui-resizable side-nav-resizable">
  <div id="nav-tree">
    <div id="nav-tree-contents">
      <div id="nav-sync" class="sync"></div>
    </div>
  </div>
  <div id="splitbar" style="-moz-user-select:none;" 
       class="ui-resizable-handle">
  </div>
</div>
<script type="text/javascript">
/* @license magnet:?xt=urn:btih:d3d9a9a6595521f9666a5e94cc830dab83b65699&amp;dn=expat.txt MIT */
$(document).ready(function(){initNavTree('man_coap_observe.html',''); initResizable(); });
/* @license-end */
</script>
<div id="doc-content">
<!-- window showing the filter options -->
<div id="MSearchSelectWindow"
     onmouseover="return searchBox.OnSearchSelectShow()"
     onmouseout="return searchBox.OnSearchSelectHide()"
     onkeydown="return searchBox.OnSearchSelectKey(event)">
</div>

<!-- iframe showing the search results (closed by default) -->
<div id="MSearchResultsWindow">
<div id="MSearchResults">
<div class="SRPage">
<div id="SRIndex">
<div id="SRResults"></div>
<div class="SRStatus" id="Loading">Loading...</div>
<div class="SRStatus" id="Searching">Searching...</div>
<div class="SRStatus" id="NoMatches">No Matches</div>
</div>
</div>
</div>
</div>

<div><div class="header">
  <div class="headertitle"><div class="title">coap_observe(3)</div></div>
</div><!--header-->
<div class="contents">
<div class="textblock"><?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"><html xmlns="http://www.w3.org/1999/xhtml"><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /><title>coap_observe</title><link rel="stylesheet" type="text/css" href="docbook-xsl.css" /><meta name="generator" content="DocBook XSL Stylesheets Vsnapshot" /></head><body><div xml:lang="en" class="refentry" lang="en"><a id="id1337"></a><div class="titlepage"></div><div class="refnamediv"><h2>NAME</h2><p>coap_observe, coap_resource_set_get_observable, coap_resource_notify_observers, coap_resource_get_uri_path, coap_find_observer, coap_delete_observer, coap_delete_observers — work with CoAP observe</p></div><div class="refsynopsisdiv"><a id="_synopsis"></a><h2>SYNOPSIS</h2><p><span class="strong"><strong>#include &lt;coap2/coap.h&gt;</strong></span></p><p><span class="strong"><strong>void coap_resource_set_get_observable(coap_resource_t *<span class="emphasis"><em>resource</em></span>,
int <span class="emphasis"><em>mode</em></span>);</strong></span></p><p><span class="strong"><strong>int coap_resource_notify_observers(coap_resource_t *<span class="emphasis"><em>resource</em></span>,
const const_string_t *<span class="emphasis"><em>query</em></span>);</strong></span></p><p><span class="strong"><strong>const coap_string_t *coap_resource_get_uri_path(coap_resource_t *<span class="emphasis"><em>resource</em></span>);</strong></span></p><p><span class="strong"><strong>coap_subscription_t *coap_find_observer(coap_resource_t *<span class="emphasis"><em>resource</em></span>,
coap_session_t *<span class="emphasis"><em>session</em></span>, const const_string_t *<span class="emphasis"><em>token</em></span>);</strong></span></p><p><span class="strong"><strong>int coap_delete_observer(coap_resource_t *<span class="emphasis"><em>resource</em></span>, coap_session_t *<span class="emphasis"><em>session</em></span>,
const coap_binary_t *<span class="emphasis"><em>token</em></span>);</strong></span></p><p><span class="strong"><strong>void coap_delete_observers(coap_context_t *<span class="emphasis"><em>context</em></span>, coap_session_t *<span class="emphasis"><em>session</em></span>);</strong></span></p><p>Link with <span class="strong"><strong>-lcoap-2</strong></span>, <span class="strong"><strong>-lcoap-2-gnutls</strong></span>,
<span class="strong"><strong>-lcoap-2-openssl</strong></span> or
<span class="strong"><strong>-lcoap-2-tinydtls</strong></span> depending on your (D)TLS library
type.</p></div><div class="refsect1"><a id="_description"></a><h2>DESCRIPTION</h2><p>RFC 7641 extends the CoAP protocol to be able to monitor the state of a
resource over time.</p><p>This enables clients to "observe" resources with a defined query, i.e., to
retrieve a representation of a resource and keep this representation updated
by the server over a period of time.</p><p>The server has to flag a resource as "observable", and then the client has
to request in a GET request that it wants to observe this resource by the use
of the COAP_OPTION_OBSERVE Option with a value of COAP_OBSERVE_ESTABLISH.
Optionally, the client can specify query options for the resource.</p><p>To remove the "observe" subscription, the client has to issue a GET request
with the COAP_OPTION_OBSERVE Option with a value of COAP_OBSERVE_CANCEL.
Alternatively, the server can remove a subscription by calling
<span class="strong"><strong>coap_delete_observer</strong></span>() or <span class="strong"><strong>coap_delete_observers</strong></span>(), but this does not
notify the client that the subscription has been removed.</p><p>The underlying library adds in and removes "subscribers" to the resource as
appropriate in the server side logic.</p><p>Within the server application, it needs to determine that there is a change of
state of the resource under observation, and then cause the CoAP library
layer to initiate a "fake GET request" so that an observe GET response
gets sent back to all the clients that are observing the resource.  The
appropriate GET handler within the server application is called to fill in the
response packet with the appropriate information. This "fake GET request" is
triggered by a call to <span class="strong"><strong>coap_resource_notify_observers</strong></span>().</p><p>The call to <span class="strong"><strong>coap_run_once</strong></span>() in the main server application i/o loop will do
all the necessary processing of sending any outstanding "fake GET requests".</p><p>Whenever the server sends a copy of the state of the "observed" resource to
the client, it will use the same token used by the client when the client
requested the "observe".  The client will receive this observe response
in the handler defined by <span class="strong"><strong>coap_register_response_handler</strong></span>(3).  It is the
responsibility of the client application to match the supplied token and
update the appropriate internal information.</p><p>The <span class="strong"><strong>coap_resource_set_get_observable</strong></span>() function enables or disables the
observable status of the <span class="emphasis"><em>resource</em></span> by the setting of <span class="emphasis"><em>mode</em></span>.  If <span class="emphasis"><em>mode</em></span> is
1, then the <span class="emphasis"><em>resource</em></span> is observable.  If <span class="emphasis"><em>mode</em></span> is 0, then the
<span class="emphasis"><em>resource</em></span> is no longer observable.</p><p><span class="strong"><strong>NOTE:</strong></span> It is not possible for the Unknown Resource, created by
<span class="strong"><strong>coap_resource_unknown_init</strong></span>(3), to be observable as the Uri-Path is not known
when libcoap creates a "fake GET request".  The Unknown Resource PUT
handler must create a new resource and mark the resource as "observable" if
a specific resource needs to be observable.  The application must then
manage the deleteion of the resource at the appropriate time.</p><p><span class="strong"><strong>NOTE:</strong></span> The type (confirmable or non-confirmable) of the triggered observe
GET response is determined not by the initial GET request, but independently
by the server as per RFC 7641 3.5. Transmission.  This is controlled by the
flags (one of COAP_RESOURCE_FLAGS_NOTIFY_NON or COAP_RESOURCE_FLAGS_NOTIFY_CON)
used when creating the resource using <span class="strong"><strong>coap_resource_init</strong></span>(3).
Furthermore, the server must send at least one "observe" response as
confirmable, when generally sending non-confirmable,  every 24 hours.
libcoap handles this by sending every fifth (COAP_OBS_MAX_NON) response as a
confirmable response for detection that the client is still responding.</p><p>The <span class="strong"><strong>coap_resource_notify_observers</strong></span>() function needs to be called whenever the
server application determines that there has been a change to the state of
<span class="emphasis"><em>resource</em></span>, possibly only matching a specific <span class="emphasis"><em>query</em></span> if <span class="emphasis"><em>query</em></span> is not NULL.</p><p>The <span class="strong"><strong>coap_resource_get_uri_path</strong></span>() function is used to obtain the UriPath of
the <span class="emphasis"><em>resource</em></span> definion.</p><p>The <span class="strong"><strong>coap_find_observer</strong></span>() function is used to check whether the current GET
request as determined from <span class="emphasis"><em>resource</em></span>, <span class="emphasis"><em>session</em></span> and <span class="emphasis"><em>token</em></span> is currently
being observed or not.</p><p>The <span class="strong"><strong>coap_delete_observer</strong></span>() function deletes the specific observer associated
with <span class="emphasis"><em>resource</em></span>, <span class="emphasis"><em>session</em></span> and has <span class="emphasis"><em>token</em></span>.</p><p>The <span class="strong"><strong>coap_delete_observers</strong></span>() function is used to delete all observers
associated with the <span class="emphasis"><em>session</em></span> that is a part of the <span class="emphasis"><em>context</em></span>.</p></div><div class="refsect1"><a id="_return_values"></a><h2>RETURN VALUES</h2><p>The <span class="strong"><strong>coap_resource_get_uri_path</strong></span>() function returns the uri_path or NULL if
there was a failure.</p><p>The <span class="strong"><strong>coap_find_observer</strong></span>() function returns the subscription or NULL if there
was a failure.</p><p>The <span class="strong"><strong>coap_resource_set_get_observable</strong></span>() function return 0 on failure, 1 on
success.</p><p>The <span class="strong"><strong>coap_delete_observer</strong></span>() function return 0 on failure, 1 on success.</p></div><div class="refsect1"><a id="_examples"></a><h2>EXAMPLES</h2><p><span class="strong"><strong>Simple Time Server</strong></span></p><pre class="programlisting">#include &lt;coap2/coap.h&gt;

coap_resource_t *time_resource = NULL;

static int check_if_time_resource_has_changed(coap_resource_t *resource) {
  return 1;
}

/* specific GET "time" handler, called from hnd_get_generic() */

static void
hnd_get_time(coap_context_t *context, coap_resource_t *resource,
coap_session_t *session, coap_pdu_t *request, coap_string_t *token,
coap_string_t *query, coap_pdu_t *response) {

  unsigned char buf[40];
  size_t len;
  time_t now;

  /* ... Additional analysis code for resource, request pdu etc.  ... */

  /* After analysis, generate a suitable response */

  /* Note that token, if set, is already in the response pdu */

  now = time(NULL);

  if (query != NULL &amp;&amp; coap_string_equal(query, coap_make_str_const("secs"))) {
    /* Output secs since Jan 1 1970 */
    len = snprintf((char *)buf, sizeof(buf), "%lu", now);
  }
  else {
    /* Output human-readable time */
    struct tm *tmp;
    tmp = gmtime(&amp;now);
    if (!tmp) {
      /* If 'now' is not valid */
      response-&gt;code = COAP_RESPONSE_CODE(404);
      return;
    }
    len = strftime((char *)buf, sizeof(buf), "%b %d %H:%M:%S", tmp);
  }
  /*
   * Invoke coap_add_data_blocked_response() to do all the hard work.
   *
   * Define the format - COAP_MEDIATYPE_TEXT_PLAIN - to add in
   * Define how long this response is valid for (secs) - 1 - to add in.
   *
   * OBSERVE Option added internally if needed within the function
   * BLOCK2 Option added internally if output too large
   * ETAG Option added internally
   */
  coap_add_data_blocked_response(resource, session, request, response, token,
                                 COAP_MEDIATYPE_TEXT_PLAIN, 1,
                                 len,
                                 buf);

  /*
   * As resource-&gt;code has been updated in coap_add_data_blocked_response(),
   * the response pdu will be transmitted by the underlying library.
   */

}

/* Generic GET handler */

static void
hnd_get_generic(coap_context_t *ctx, coap_resource_t *resource,
coap_session_t *session, coap_pdu_t *request, coap_string_t *token,
coap_string_t *query, coap_pdu_t *response) {

  coap_str_const_t *uri_path = coap_resource_get_uri_path(resource);

  if (!uri_path) {
    /* Unexpected Failure */
    response-&gt;code = COAP_RESPONSE_CODE(400);
    return;
  }

  /* Is this the "time" resource" ? */
  if (coap_string_equal(uri_path, coap_make_str_const("time"))) {
    hnd_get_time(ctx, resource, session, request, token, query,
                 response);
    return;
  }

  /* Other resources code */

  /* Failure response */
  response-&gt;code = COAP_RESPONSE_CODE(400);
}

/* Initialize generic GET handler */

static void
init_resources(coap_context_t *ctx)
{

  coap_resource_t *r;

  /* Create a resource to return return or update time */
  r = coap_resource_init(coap_make_str_const("time"),
                         COAP_RESOURCE_FLAGS_NOTIFY_CON);

  /* We are using a generic GET handler here */
  coap_register_handler(r, COAP_REQUEST_GET, hnd_get_generic);

  coap_resource_set_get_observable(r, 1);

  coap_add_resource(ctx, r);
  time_resource = r;

}

int main(int argc, char *argv[]){

  coap_context_t *ctx = NULL;
  coap_endpoint_t *ep = NULL;
  coap_address_t addr;
  unsigned wait_ms;

  /* Create the libcoap context */
  ctx = coap_new_context(NULL);
  if (!ctx) {
    exit(1);
  }
  coap_address_init(&amp;addr);
  addr.addr.sa.sa_family = AF_INET;
  addr.addr.sin.sin_port = ntohs(COAP_DEFAULT_PORT);
  ep = coap_new_endpoint(ctx, &amp;addr, COAP_PROTO_UDP);

  /* Other Set up Code */

  init_resources(ctx);

  wait_ms = COAP_RESOURCE_CHECK_TIME * 1000;

  while (1) {
    int result = coap_run_once( ctx, wait_ms );
    if ( result &lt; 0 ) {
      break;
    } else if ( result &amp;&amp; (unsigned)result &lt; wait_ms ) {
      /* decrement if there is a result wait time returned */
      wait_ms -= result;
    } else {
      /*
       * result == 0, or result &gt;= wait_ms
       * (wait_ms could have decremented to a small value, below
       * the granularity of the timer in coap_run_once() and hence
       * result == 0)
       */
      time_t t_now = time(NULL);
      if (t_last != t_now) {
        /* Happens once per second */
        int i;
        t_last = t_now;
        if (time_resource) {
          coap_resource_notify_observers(time_resource, NULL);
        }
      }
      if (result) {
        /* result must have been &gt;= wait_ms, so reset wait_ms */
        wait_ms = COAP_RESOURCE_CHECK_TIME * 1000;
      }
    }
  }
  exit(0);

}</pre><p><span class="strong"><strong>Client Observe Request Setup</strong></span></p><pre class="programlisting">#include &lt;coap2/coap.h&gt;

/* Usually, requests are sent confirmable */

static unsigned char msgtype = COAP_MESSAGE_CON;

static unsigned int token = 0;

static coap_pdu_t *
coap_new_request(coap_context_t *context, coap_session_t *session, char request_code,
coap_optlist_t **options, unsigned char *data, size_t length, int observe) {

  coap_pdu_t *pdu;
  coap_optlist_t *opt;
  (void)context;

  /* Create the pdu with the appropriate options */
  pdu = coap_pdu_init(msgtype, request_code, coap_new_message_id(session),
                      coap_session_max_pdu_size(session));
  if (!pdu)
    return NULL;

  /*
   * Create uniqueness token for this request for handling unsolicited /
   * delayed responses
   */
  token++;
  if (!coap_add_token(pdu, sizeof(token), (unsigned char*)&amp;token)) {
    coap_log(LOG_DEBUG, "cannot add token to request\n");
    goto error;
  }

  if (request_code == COAP_REQUEST_GET &amp;&amp; observe) {
    /* Indicate that we want to observe this resource */
    if (!coap_insert_optlist(options,
                             coap_new_optlist(COAP_OPTION_OBSERVE,
                                         COAP_OBSERVE_ESTABLISH, NULL)))
      goto error;
  }

  /* ... Other code / options etc. ... */

  /* Add in all the options (after internal sorting) to the pdu */
  if (!coap_add_optlist_pdu(pdu, options))
    goto error;

  if (data &amp;&amp; length) {
    /* Add in the specified data */
    if (!coap_add_data(pdu, length, data))
      goto error;
  }

  return pdu;

error:

  coap_delete_pdu(pdu);
  return NULL;

}</pre></div><div class="refsect1"><a id="_see_also"></a><h2>SEE ALSO</h2><p><a href="man_coap_attribute.html" target="_self"><span class="strong"><strong>coap_attribute</strong></span>(3)</a>, <a href="man_coap_context.html" target="_self"><span class="strong"><strong>coap_context</strong></span>(3)</a>, <a href="man_coap_handler.html" target="_self"><span class="strong"><strong>coap_handler</strong></span>(3)</a>, <a href="man_coap_pdu_setup.html" target="_self"><span class="strong"><strong>coap_pdu_setup</strong></span>(3)</a>
and <a href="man_coap_resource.html" target="_self"><span class="strong"><strong>coap_resource</strong></span>(3)</a></p></div><div class="refsect1"><a id="_further_information"></a><h2>FURTHER INFORMATION</h2><p>"RFC7252: The Constrained Application Protocol (CoAP)"
"RFC7641: Observing Resources in the Constrained Application Protocol (CoAP)"</p></div><div class="refsect1"><a id="_bugs"></a><h2>BUGS</h2><p>Please report bugs on the mailing list for libcoap:
<a class="ulink" href="mailto:libcoap-developers@lists.sourceforge.net" target="_top">libcoap-developers@lists.sourceforge.net</a></p></div><div class="refsect1"><a id="_authors"></a><h2>AUTHORS</h2><p>The libcoap project &lt;<a class="ulink" href="mailto:libcoap-developers@lists.sourceforge.net" target="_top">libcoap-developers@lists.sourceforge.net</a>&gt;</p></div></div></body></html> coap_observe(3)</p>
</div></div><!-- contents -->
</div><!-- PageDoc -->
</div><!-- doc-content -->
<!-- start footer part -->
<div id="nav-path" class="navpath"><!-- id is needed for treeview function! -->
  <ul>
    <li class="footer">Generated on Fri Dec 27 2024 09:57:44 for libcoap by <a href="https://www.doxygen.org/index.html"><img class="footer" src="doxygen.svg" width="104" height="31" alt="doxygen"/></a> 1.9.8 </li>
  </ul>
</div>
</body>
</html>
